	%{ open Ast %}

%token PLUS MINUS TIMES DIVIDE EQ NEQ GT LT GEQ LEQ AND OR NOT FPLUS FMINUS FTIMES FDIVIDE ASSIGN LPAREN RPAREN LBRACE RBRACE COMMA SEMI INT STRINGV DQUOTATION SQUOTATION LSQUA RSQUA PERIOD RETURN FLO WHILE IF ELSE SHASH ADD SLIST CREATE SLHASH MEM FIND PRINT INTERSECT GETDISTANCE STRCMP EOF 
%token <int> LITERAL
%token <float> FLOAT
%token <string> ID
%token <string> STR
%token <char> CHAR


%left PLUS MINUS
%left TIMES DIVIDE

%start program
%type < Ast.expr> expr
%type < Ast.stmt> stmt
%type < Ast.func> fdel
%type < Ast.program> program

%%

expr:
  LPAREN expr PLUS   expr RPAREN { Binop($2, Add, $4) }
| LPAREN expr MINUS  expr RPAREN { Binop($2, Sub, $4) }
| LPAREN expr TIMES  expr RPAREN { Binop($2, Mul, $4) }
| LPAREN expr DIVIDE expr RPAREN { Binop($2, Div, $4) }
| LPAREN expr EQ expr RPAREN { Binop($2, Equal, $4) }
| LPAREN expr NEQ expr RPAREN { Binop($2, Neq, $4) }
| LPAREN expr GT expr RPAREN { Binop($2, Greater , $4) }
| LPAREN expr LT expr RPAREN { Binop($2, Less, $4) }
| LPAREN expr GEQ expr RPAREN { Binop($2, Geq, $4) }
| LPAREN expr LEQ expr RPAREN { Binop($2, Leq, $4) }
| LPAREN expr AND expr RPAREN { Binop($2, And, $4) }
| LPAREN expr OR expr RPAREN { Binop($2, Or, $4) }
| LPAREN expr FPLUS   expr RPAREN { FBinop($2, Fadd, $4) }
| LPAREN expr FMINUS  expr RPAREN { FBinop($2, Fsub, $4) }
| LPAREN expr FTIMES  expr RPAREN { FBinop($2, Fmul, $4) }
| LPAREN expr FDIVIDE expr RPAREN { FBinop($2, Fdiv, $4) }
| NOT expr         { Not($2) }
| LITERAL          { Lit($1) }
| FLOAT            { Float($1)}
| ID               { Id($1)} 
| CHAR             { Char($1)}
| STR              { Str($1)}
| ID LPAREN actuals_opt RPAREN {Call($1,$3)}
| PRINT LPAREN ID RPAREN      {Print ($3)}
| LSQUA string_list RSQUA     {Slist($2)}
| INT ID           {Int($2)}
| FLO ID           {Flo($2)}
| STRINGV ID        {Stringv($2)}
| SLIST ID         {StringList($2)}
| SLIST PERIOD ADD ID expr {StringListAdd($4,$5) }
| ID ASSIGN expr   {Assign($1,$3)}
| INT ID LSQUA LITERAL RSQUA {IntArray($2,$4)}
| ID LSQUA expr RSQUA PERIOD ID {ObjArray($1,$3,$6)}
| ID LSQUA LITERAL RSQUA PERIOD ID PERIOD ID {Objpoint($1,$3,$6,$8)}
| ID PERIOD ID {Onedot($1,$3)}
| ID LSQUA expr RSQUA PERIOD ID LSQUA expr RSQUA PERIOD ID {Twodot($1,$3,$6,$8,$11)}
| ID LSQUA LITERAL RSQUA ASSIGN expr {ArrAssign($1,$3,$6)}
| SHASH PERIOD ADD ID STR expr {Sadd ($4,$5,$6)}
| SHASH PERIOD MEM ID STR  {Smem($4,$5)}
| SHASH PERIOD FIND ID STR  {Sfind($4,$5)}
| ID PERIOD ADD STR expr {SLadd ($1,$4,$5)}
| ID PERIOD MEM STR {SLmem($1,$4)}
| ID PERIOD FIND STR {SLfind($1,$4)}
| SHASH PERIOD CREATE ID   {Scre($4)}
| SLHASH ID   {SLcre($2)}
| RETURN expr      {Return($2)}
| INTERSECT LPAREN expr COMMA expr RPAREN {Intersect($3,$5)}
| GETDISTANCE LPAREN expr COMMA expr RPAREN {GetDistance($3, $5)}
| STRCMP LPAREN expr COMMA expr RPAREN  {Strcmp($3,$5)}


stmt:
  expr SEMI        {Expr($1)}
| LBRACE stmt_list RBRACE        {Block(List.rev $2)}
| WHILE LPAREN expr RPAREN stmt  {While($3,$5)}
| IF LPAREN expr RPAREN stmt ELSE stmt {If($3,$5,$7)}

program:
                   {[]}
| program fdel     {$2::$1}

fdel:
 ID LPAREN formals_opt RPAREN LBRACE stmt_list RBRACE
{{ fname=$1; formals=$3; body=Block(List.rev $6); }}

formals_opt:
                   {[]}
 | formal_list     {List.rev $1}

formal_list:
  var               {[$1]}
| formal_list COMMA var {$3::$1} 




var:
  INT ID                {$2}
| STRINGV ID            {$2}
| FLO ID                {$2}


stmt_list:
                   {[]}
|  stmt_list stmt   {$2::$1}

actuals_list:
  expr         {[$1]}
| actuals_list COMMA expr {$3 :: $1}

actuals_opt:
               {[]}
| actuals_list {List.rev $1}

string_list:
  STR               {[$1]}
| string_list SEMI STR {$3::$1}


